package com.zzxx.wechat.common.aop;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.Instant;
import java.util.UUID;

@Slf4j
@Aspect
@Configuration
public class LogControllerAop {

    @Pointcut("within(com.zzxx.wechat.controller.*) ")
    public void serviceLog() {

    }

    @Around("serviceLog()")
    public Object doAroundService(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            Instant instStart = Instant.now();
            getAndSetTraceId();
            String url = "";
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (requestAttributes != null) {
                url = requestAttributes.getRequest().getRequestURI();
            }
            log.info("执行class_method={}, url={}, args={}",
                    proceedingJoinPoint.getSignature().getDeclaringTypeName() + "." + proceedingJoinPoint
                            .getSignature().getName(), url, proceedingJoinPoint.getArgs());
            Object object = proceedingJoinPoint.proceed();
            Instant instEnd = Instant.now();
            long timeDifference = Duration.between(instStart, instEnd).toMillis();
            BigDecimal divideUnsigned = BigDecimal.valueOf(timeDifference)
                    .divide(BigDecimal.valueOf(1000L), 3, RoundingMode.HALF_UP);
            log.info("执行class_method={},url={}, 耗时={}秒,result={}", proceedingJoinPoint.getSignature().getDeclaringTypeName() + "." + proceedingJoinPoint
                    .getSignature().getName(), url, divideUnsigned, JSON.toJSON(object));
            MDC.clear();
            return object;
        } catch (Throwable throwable) {
            log.error("发现异常：class_method={}, args={}, 异常信息:{}", proceedingJoinPoint
                            .getSignature().getDeclaringTypeName() + "." + proceedingJoinPoint.getSignature().getName(),
                    proceedingJoinPoint.getArgs(), throwable.getMessage());
            //抛出异常，统一拦截处理
            throw throwable;
        }
    }


    private void getAndSetTraceId() {
        String traceId = MDC.get("traceId");
        if (StringUtils.isBlank(traceId)) {
            HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
            traceId = request.getHeader("traceId");
            if (StringUtils.isBlank(traceId)) {
                MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
            } else {
                MDC.put("traceId", traceId);
            }
        }
    }
}
